package fr.neyb.wesb.core.data.compare;

import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;

import fr.neyb.framework.exceptions.TechnicalException;
import fr.neyb.framework.util.Tools;
import fr.neyb.wesb.core.data.content.Field;

public class FieldComparatorManager {

	public static FieldComparatorManager getInstance() {
		return Initializer.instance;
	}

	private static class Initializer {
		public static FieldComparatorManager instance = new FieldComparatorManager();
	}

	private static class Key<C extends Comparator<Field>> {
		private final Class<C> clazz;
		private final Order o;

		public Key(Class<C> clazz, Order o) {
			Tools.checkNotNull(clazz, o);
			this.clazz = clazz;
			this.o = o;
		}

		@Override
		public int hashCode() {
			return Tools.hashcode(clazz, o);
		}

		@Override
		public boolean equals(Object obj) {
			if (obj == this)
				return true;

			if (!(obj instanceof Key))
				return false;

			Key<?> objAsKey = (Key<?>) obj;
			return clazz.equals(objAsKey.clazz) && o.equals(objAsKey.o);
		}
	}

	private Map<Key<?>, Comparator<Field>> instances = Collections
			.synchronizedMap(new HashMap<Key<?>, Comparator<Field>>());

	public <T extends Comparator<Field>> T getFieldComparator(
			Class<T> clazz, Order order) {
		Key<T> k = new Key<>(clazz, order);

		T result = searchFieldComparator(k);
		if (result != null)
			return result;

		result = createFieldComparator(k);

		instances.put(k, result);

		return result;
	}

	private <T extends Comparator<Field>> T createFieldComparator(Key<T> k) {
		try {
			return k.clazz.getConstructor(Order.class).newInstance(k.o);
		} catch (InstantiationException | IllegalAccessException
				| IllegalArgumentException | InvocationTargetException
				| NoSuchMethodException | SecurityException e) {
			throw new TechnicalException(e);
		}
	}

	@SuppressWarnings("unchecked")
	//controlled adds
	private <T extends Comparator<Field>> T searchFieldComparator(
			Key<T> k) {
		return (T) instances.get(k);
	}
}
